package utils

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// 将字符串转换为io.Reader
func StrToReader(str string) *strings.Reader {
	return strings.NewReader(str)
}

// 将字符串转换为byte
func StrToByte(str string) []byte {
	return []byte(str)
}

// byte转字符串
func ByteToStr(b []byte) string {
	return string(b)
}

// 将byte转换为io.Reader
func ByteToReader(b []byte) *strings.Reader {
	return strings.NewReader(string(b))
}

// 将io.Reader转换为byte
func ReaderToByte(r *strings.Reader) []byte {
	b := make([]byte, r.Len())
	read, err := r.Read(b)
	if err != nil {
		return nil
	}
	if read != len(b) {
		return nil
	}
	return b
}

// 字符串按行读取
func ReadLine(str string) []string {
	split := strings.Split(str, "\n")
	//清除空行和空白
	var returnData []string
	for _, v := range split {
		if strings.TrimSpace(v) != "" {
			returnData = append(returnData, strings.TrimSpace(v))
		}
	}
	return returnData
}

// 获取文件多少行
func GetFileLine(filePath string) int {
	file, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	var i int
	for {
		_, _, err := r.ReadLine()
		if err == io.EOF {
			break
		}
		i++
	}
	return i
}

// 计算到指定行的字节数
func GetFileLineByte(filePath string, line int) int64 {
	file, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	var i int
	var byteNum int64
	for {
		lineByteNum, _, err := r.ReadLine()
		if err == io.EOF {
			break
		}
		i++
		//转换为字节
		strToByte := StrToByte(string(lineByteNum))
		//因为每行有换行符需要+2字节
		byteNum += int64(len(strToByte)) + 2
		if i == line {
			break
		}
	}
	if byteNum == 0 {
		return 0
	}
	//最后一行没有换行符,那么需要减2字节
	return byteNum - 2
}

// 文件按行读取,返回[]string
func ReadFileLine(filePath string) []string {
	file, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	var returnData []string
	r := bufio.NewReader(file)
	for {
		line, _, err := r.ReadLine()
		if err == io.EOF {
			break
		}
		returnData = append(returnData, string(line))
	}
	return returnData
}

// 文件按行读取,func(string) error
func ReadFileLineF(filePath string, f func(string) error) {
	file, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	for {

		line, _, err := r.ReadLine()
		if err == io.EOF {
			break
		}
		err = f(string(line))
		if err != nil {
			panic(err)
		}
	}
}

/*
*
  - 读取文件内容
  - @param  {[string]} filePath string [文件路径]
  - @param  {[int64]} offset   int64  [偏移量]   从文件开始位置偏移offset个字节
  - @param  {[int64]} num      int64  [读取字节数]
  - @return {[string]}                 [文件内容]
*/
func ReadFileByte(filePath string, offset int64, num int64) []byte {
	file, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	_, err = file.Seek(offset, 0) //0表示从文件开始位置偏移offset个字节
	if err != nil {
		panic(err)
	}
	b := make([]byte, num) //num表示读取num个字节
	_, err = file.Read(b)
	if err != nil {
		panic(err)
	}
	return b
}

// 读取到指定第一个分割符
func ReadFileButeDelim(filePath string, delim byte) []byte {
	file, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	b, err := r.ReadBytes(delim)
	if err != nil {
		panic(err)
	}
	return b
}

// 将字节写入文件
func WriteFileByte(filePath string, isApp bool, b []byte) {
	var err error
	var file *os.File
	if isApp {
		file, err = os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
	} else {
		file, err = os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0755)
	}
	if err != nil {
		panic(err)
	}
	defer file.Close()
	_, err = file.Write(b)
	if err != nil {
		panic(err)
	}
}

// 从文件指定位置开始写入,如果存在内容则覆盖
func WriteFileByteOffset(filePath string, offset int64, b []byte) {
	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	_, err = file.Seek(offset, 0)
	if err != nil {
		panic(err)
	}
	_, err = file.Write(b)
	if err != nil {
		panic(err)
	}
}

/**
 *  @Description: 读写文件高级函数,可控制读写位置,可控制读写字节数,可控制读写次数
 *	@param   r_filePath string  读取文件路径
 *	@param   r_offset   int     读取位置
 *	@param   R_num      int     每次读取字节数
 *	@param   R_count    int     读取次数  ?<1表示读取到文件末尾 ,1表示读取一次,2表示读取两次,以此类推
 *  @param   r_func     func(rbyte []byte, ro *os.File, wo *os.File) []byte    读取后的字节处理函数
 *  @param   w_filePath string  写入文件路径
 *	@param   w_offset   int     写入位置 ,如果?<0表示写入到文件末尾
 */
func ReadWriteFile(
	r_filePath string, r_offset int64, R_num int64, R_count int, r_func func(rbyte []byte, ro *os.File, wo *os.File) []byte,
	w_filePath string, w_offset int64) {

	r_file, err := os.OpenFile(r_filePath, os.O_RDONLY, 0755)
	if err != nil {
		panic(err)
	}
	defer r_file.Close()
	var w_file *os.File
	if w_offset < 0 {
		w_file, err = os.OpenFile(w_filePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
	} else {
		w_file, err = os.OpenFile(w_filePath, os.O_WRONLY|os.O_CREATE, 0755)
	}
	if err != nil {
		panic(err)
	}
	defer w_file.Close()
	//从什么位置开始读取
	_, err = r_file.Seek(r_offset, 0)
	if err != nil {
		panic(err)
	}
	//从什么位置开始写入
	if w_offset > 0 {
		_, err = w_file.Seek(w_offset, 0)
		if err != nil {
			panic(err)
		}
	}

	//如果没有传入读取后的字节处理函数,则默认不处理
	if r_func == nil {
		r_func = func(rbyte []byte, ro *os.File, wo *os.File) []byte {
			return rbyte
		}
	}

	//每次读取多少字节
	b := make([]byte, R_num)
	if R_count < 1 {
		for {
			n, r_err := r_file.Read(b)
			if r_err == io.EOF {
				break
			}
			rFunc := r_func(b[:n], r_file, w_file)
			_, w_err := w_file.Write(rFunc)
			if w_err != nil {
				panic(err)
			}
		}
	} else {
		for i := 0; i < R_count; i++ {
			n, r_err := r_file.Read(b)
			if r_err == io.EOF {
				break
			}
			rFunc := r_func(b[:n], r_file, w_file)
			_, w_err := w_file.Write(rFunc)
			if w_err != nil {
				panic(err)
			}
		}
	}
}

// 下载网络文件
func DownloadFile(url string, filePath string) {
	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	_, err = io.Copy(file, resp.Body)
	if err != nil {
		panic(err)
	}
}

// 批量下载网络文件
func DownloadFiles(urls []string, filePaths []string) {
	for i, url := range urls {
		DownloadFile(url, filePaths[i])
	}
}

// 上传单个文件
/**
 *  @Description: 上传单个文件
 *	@param   url       string  上传地址
 *	@param   fieldName string  上传字段名
 *	@param   filePath  string  上传文件路径
 */
func UploadFile(url, fieldName string, filePath string) {
	UploadFiles(url, fieldName, []string{filePath})
}

// 批量上传文件
/**
 *  @Description: 批量上传文件
 *	@param   url       string  上传地址
 *	@param   fieldName string  上传字段名
 *	@param   filePaths []string  上传文件路径
 */
func UploadFiles(url, fieldName string, filePaths []string) {
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	for _, filePath := range filePaths {
		file, err := os.OpenFile(filePath, os.O_RDONLY, 0755)
		if err != nil {
			panic(err)
		}
		defer file.Close()
		part, err := writer.CreateFormFile(fieldName, filepath.Base(filePath))
		if err != nil {
			panic(err)
		}
		_, err = io.Copy(part, file)
		if err != nil {
			panic(err)
		}
	}
	writer.Close()
	resp, err := http.Post(url, writer.FormDataContentType(), body)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	b, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b))
}
